#include "oled.h"
#include "oled_font.h"

/**
 * @brief define the OLED parameters
 * 
 */
#define X_level_low		0x02
#define X_level_high	0x10
#define	brightness		0xFF
#define X_width 		128
#define Y_width 		64

/**
 * @brief define the OLED command and write_data
 * 
 */
#define OLED_CMD  0
#define OLED_DATA 1
#define OLED_MODE 0

void OLED_Init(void);
void OLED_Clear(void);
void OLED_WR_Byte(unsigned char write_data, unsigned char cmd);
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char chr, unsigned char Char_Size);
void OLED_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len, unsigned char size);
void OLED_ShowString(unsigned char x, unsigned char y, unsigned char *p, unsigned char Char_Size);	 
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_ShowChinese(unsigned char x, unsigned char y, unsigned char no);

/**
 * @brief write data to OLED
 * 
 * @param dat the write_data to be written
 * @param cmd 
 */
void OLED_WR_Byte(unsigned char write_data, unsigned char cmd)
{
	if (cmd)
	{
		Write_OLED_IIC_Data(write_data);
	}
	else
	{
		Write_OLED_IIC_Command(write_data);
	}
}

/**
 * @brief set the position of OLED
 * 
 * @param x x position
 * @param y y position
 */
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
	OLED_WR_Byte(0xb0 + y, OLED_CMD);
	OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
	OLED_WR_Byte((x & 0x0f), OLED_CMD);
}

/**
 * @brief clear the OLED screen
 * 
 */
void OLED_Clear(void)
{
	unsigned char i = 0, n = 0;
	for (i = 0;i < 8;i++)
	{
		OLED_WR_Byte(0xb0 + i, OLED_CMD);
		OLED_WR_Byte(0x00, OLED_CMD);
		OLED_WR_Byte(0x10, OLED_CMD); 
		for (n = 0;n < 128;n++)
		{
			OLED_WR_Byte(0, OLED_DATA);
		}
	}
}

/**
 * @brief show a character on OLED
 * 
 * @param x x position
 * @param y y position
 * @param chr character to be shown
 * @param Char_Size character size
 */
void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char chr, unsigned char Char_Size)
{
	unsigned char c = 0, i = 0;
	c = chr - ' ';	

	if (x > X_width - 1)
	{
		x = 0;
		y = y + 2;
	}

	if (Char_Size == 16)
	{
		OLED_Set_Pos(x, y);

		for (i = 0;i < 8;i++)
		{
			OLED_WR_Byte(F8X16[c * 16 + i], OLED_DATA);
		}

		OLED_Set_Pos(x, y + 1);
		for (i = 0;i < 8;i++)
		{
			OLED_WR_Byte(F8X16[c * 16 + i + 8], OLED_DATA);
		}
	}
	else
	{
		OLED_Set_Pos(x, y);

		for (i = 0;i < 6;i++)
		{
			OLED_WR_Byte(F6x8[c][i], OLED_DATA);
		}

	}
}

/**
 * @brief show 
 * 
 * @param m 
 * @param n 
 * @return unsigned int 
 */
unsigned int oled_pow(unsigned char m, unsigned char n)
{
	unsigned int result = 1;
	while (n--)result *= m;
	return result;
}

/**
 * @brief show a number on OLED
 * 
 * @param x x position
 * @param y y position
 * @param num the number to be shown
 * @param len the length of the number
 * @param size2 the size of the number
 */
void OLED_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len, unsigned char size2)
{
	unsigned char t, temp;
	unsigned char enshow = 0;
	for (t = 0;t < len;t++)
	{
		temp = (num / oled_pow(10, len - t - 1)) % 10;
		if (enshow == 0 && t < (len - 1))
		{
			if (temp == 0)
			{
				if (size2 == 8)
				{
					OLED_ShowChar(x + (size2 / 2 + 2) * t, y, ' ', size2);
				}
				else if (size2 == 16)
				{
					OLED_ShowChar(x + (size2 / 2) * t, y, ' ', size2);
				}
				continue;
			}
			else enshow = 1;
		}
		
		if (size2 == 8) 
		{
			OLED_ShowChar(x + (size2 / 2 + 2) * t, y, temp + '0', size2);
		}
		else if (size2 == 16)
		{
			OLED_ShowChar(x + (size2 / 2) * t, y, temp + '0', size2);
		}
	}
}

/**
 * @brief show a string on OLED
 * 
 * @param x x position
 * @param y y position
 * @param chr the string to be shown
 * @param Char_Size the size of the character
 */
void OLED_ShowString(unsigned char x, unsigned char y, unsigned char* chr, unsigned char Char_Size)
{
	unsigned char j = 0;
	while (chr[j] != '\0')
	{
		OLED_ShowChar(x, y, chr[j], Char_Size);

		x += 8;

		if (x > 120)
		{
			x = 0;
			y += 2;
		}

		j++;
	}
}

/**
 * @brief OLED show Chinese on OLED
 * 
 * @param x x position
 * @param y y position
 * @param no 
 */
void OLED_ShowChinese(unsigned char x, unsigned char y, unsigned char no)
{
	unsigned char t, adder = 0;
	OLED_Set_Pos(x, y);
	for (t = 0;t < 16;t++)
	{
		OLED_WR_Byte(Hzk[2 * no][t], OLED_DATA);
		adder += 1;
	}
	OLED_Set_Pos(x, y + 1);
	for (t = 0;t < 16;t++)
	{
		OLED_WR_Byte(Hzk[2 * no + 1][t], OLED_DATA);
		adder += 1;
	}
}

/**
 * @brief OLED initialization
 * 
 */
void OLED_Init(void)
{
	OLED_WR_Byte(0xAE, OLED_CMD);//--display off
	OLED_WR_Byte(0x00, OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10, OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40, OLED_CMD);//--set start line address  
	OLED_WR_Byte(0xB0, OLED_CMD);//--set page address
	OLED_WR_Byte(0x81, OLED_CMD); // contract control
	OLED_WR_Byte(0xFF, OLED_CMD);//--128   
	OLED_WR_Byte(0xA1, OLED_CMD);//set segment remap 
	OLED_WR_Byte(0xA6, OLED_CMD);//--normal / reverse
	OLED_WR_Byte(0xA8, OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3F, OLED_CMD);//--1/32 duty
	OLED_WR_Byte(0xC8, OLED_CMD);//Com scan direction
	OLED_WR_Byte(0xD3, OLED_CMD);//-set display offset
	OLED_WR_Byte(0x00, OLED_CMD);//

	OLED_WR_Byte(0xD5, OLED_CMD);//set osc division
	OLED_WR_Byte(0x80, OLED_CMD);//

	OLED_WR_Byte(0xD8, OLED_CMD);//set area color mode off
	OLED_WR_Byte(0x05, OLED_CMD);//

	OLED_WR_Byte(0xD9, OLED_CMD);//Set Pre-Charge Period
	OLED_WR_Byte(0xF1, OLED_CMD);//

	OLED_WR_Byte(0xDA, OLED_CMD);//set com pin configuartion
	OLED_WR_Byte(0x12, OLED_CMD);//

	OLED_WR_Byte(0xDB, OLED_CMD);//set Vcomh
	OLED_WR_Byte(0x30, OLED_CMD);//

	OLED_WR_Byte(0x8D, OLED_CMD);//set charge pump enable
	OLED_WR_Byte(0x14, OLED_CMD);//

	OLED_WR_Byte(0xAF, OLED_CMD);//--turn on oled panel
}